
package numberporting.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import numberporting.bean.Customer;
import org.codehaus.jettison.AbstractXMLStreamReader;
import org.codehaus.jettison.AbstractXMLStreamWriter;
import org.codehaus.jettison.json.JSONObject;
import org.codehaus.jettison.mapped.MappedNamespaceConvention;
import org.codehaus.jettison.mapped.MappedXMLStreamReader;
import org.codehaus.jettison.mapped.MappedXMLStreamWriter;


public class CustomerManagementClient{

    private String address;
    private String mimeType;
    private boolean useJson;

    public CustomerManagementClient(String address,boolean useJson){
        this.address = address;
        this.useJson = useJson;
        if(useJson){
            this.mimeType = "application/json";
        }else {
            this.mimeType = "application/xml";
        }
    }

    public void addCustomer(Customer customer) {
         try {
            URL url = new URL(this.address + "/"+customer.getId());
            JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{numberporting.bean.Customer.class});
            Marshaller marshaller = jaxbContext.createMarshaller();  
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
            HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
            httpCon.setRequestMethod("PUT");
            httpCon.setDoOutput(true);
            httpCon.setRequestProperty("Content-Type", this.mimeType);
            httpCon.setRequestProperty("Accept", this.mimeType);
            
            OutputStream os = httpCon.getOutputStream();

            if(this.useJson){
                // JSON from Customer Object
                // Jettison XML2JSON StreamWriter:
                MappedNamespaceConvention con = new MappedNamespaceConvention();
                StringWriter sw = new StringWriter();
                AbstractXMLStreamWriter w = new MappedXMLStreamWriter(con, sw);
                // JAXB forwards generated XML to Jettison:
                marshaller.marshal(customer, w);
                os.write(sw.toString().getBytes());
            }else{
                marshaller.marshal(customer,os);
            }
            
            // Make implicit connection to the server
            httpCon.getContentLength(); 
            httpCon.disconnect();
               os.close();
            
        } catch (JAXBException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MalformedURLException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ProtocolException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        }catch (IOException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        } 
    }

    public void deleteCustomer(String customerId) {
        try {
            URL url = new URL(this.address + "/"+customerId);
            JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{numberporting.bean.Customer.class});
            Marshaller marshaller = jaxbContext.createMarshaller();  
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
            HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
            httpCon.setRequestMethod("DELETE");
            httpCon.setDoOutput(true);
            httpCon.setRequestProperty("Content-Type", this.mimeType);
            httpCon.setRequestProperty("Accept", this.mimeType);
            //OutputStream os = httpCon.getOutputStream();
            // Make implicit connection to the server
            httpCon.getContentLength(); 
            httpCon.disconnect();
            //os.close();
            
        } catch (JAXBException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MalformedURLException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ProtocolException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        }catch (IOException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        }    
    }

    public Customer getCustomer(String customerId) throws Exception {
        Customer customer = null;
        JAXBContext jc;
        Unmarshaller unmarshaller = null;
        
        InputStream in;
        try {
            URL url = new URL(this.address + "/"+customerId);
            System.out.println("Sent HTTP GET request to "+url.toString());
            HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
            httpCon.setRequestMethod("GET");
            httpCon.setDoOutput(true);
            httpCon.setRequestProperty("Content-Type", this.mimeType);
            httpCon.setRequestProperty("Accept", this.mimeType);

            try {
                //url.openConnection();
                //in = url.openStream();
                in = httpCon.getInputStream();
            } catch (Exception ex) {
                throw new Exception("Customer \""+customerId+"\" not found!");
            }
           
            //IOUtils.copy(in, os);
            //System.out.println("xml: "+this.streamToString(in));
            jc = JAXBContext.newInstance(new Class[]{numberporting.bean.Customer.class});
            unmarshaller = jc.createUnmarshaller();
            //unmarshaller.setValidating(true);

            if(this.useJson){
                JSONObject obj = new JSONObject(this.streamToString(in));
                AbstractXMLStreamReader reader = new MappedXMLStreamReader(obj);
                //note: setting schema to null will turn validator off
                unmarshaller.setSchema(null);
                customer = (Customer) unmarshaller.unmarshal(reader);
            }else{
                customer = (Customer) unmarshaller.unmarshal(in);
            }

        } catch(IOException ex){
            System.out.println("Could not connect to server!");
            return null;
        }  catch(JAXBException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
        
        
        return customer;
    }
    
    public void updateCustomer(Customer customer) {
        try {
            URL url = new URL(this.address + "/"+customer.getId());
            JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{numberporting.bean.Customer.class});
            Marshaller marshaller = jaxbContext.createMarshaller();  
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
            HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
            httpCon.setRequestMethod("POST");
            httpCon.setDoOutput(true);
            httpCon.setRequestProperty("Content-Type", this.mimeType);
            httpCon.setRequestProperty("Accept", this.mimeType);
            OutputStream os = httpCon.getOutputStream();

            if(this.useJson){
                // JSON from Customer Object
                // Jettison XML2JSON StreamWriter:
                MappedNamespaceConvention con = new MappedNamespaceConvention();
                StringWriter sw = new StringWriter();
                AbstractXMLStreamWriter w = new MappedXMLStreamWriter(con, sw);
                // JAXB forwards generated XML to Jettison:
                marshaller.marshal(customer, w);
                os.write(sw.toString().getBytes());
            }else{
                marshaller.marshal(customer,os);
            }
            
            // Make implicit connection to the server
            httpCon.getContentLength(); 
            httpCon.disconnect();
            os.close();
            
        } catch (JAXBException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MalformedURLException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ProtocolException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        }catch (IOException ex) {
            Logger.getLogger(CustomerManagementClient.class.getName()).log(Level.SEVERE, null, ex);
        }    
        
    }
    
    
                    
    /* für xml debugging
    public static void printNodesFromList( NodeList ndList )
      {
        for( int i=0; i<ndList.getLength(); i++ )
          printNodeInfos( "ndList.item("+i+")", ndList.item(i) );
      }

    private static void printObjIfVisible( String sValName, Object obj )
      {
        if( null == obj )  return;
        String s = obj.toString();
        if( null != s && 0 < s.trim().length() && !s.trim().equals( "\n" ) )
          System.out.println( sValName + s );
      }


    public static void printNodeInfos( String sNodeName, Node node )
      {
        System.out.println(  "\n---------------------- " + sNodeName );
        if( null != node )
        {
          printObjIfVisible(   "getNodeType()        = ", "" + node.getNodeType() );
          printObjIfVisible(   "getNodeName()        = ", node.getNodeName() );
          printObjIfVisible(   "getLocalName()       = ", node.getLocalName() );
          printObjIfVisible(   "getNodeValue()       = ", node.getNodeValue() );
          if( node.hasAttributes() )
            printObjIfVisible( "getAttributes()      = ", node.getAttributes() );
          if( node.hasChildNodes() ) {
            printObjIfVisible( "getChildNodes()      = ", node.getChildNodes() );
            printObjIfVisible( "getFirstChild()      = ", node.getFirstChild() );
          }
          printObjIfVisible(   "getPreviousSibling() = ", node.getPreviousSibling() );
          printObjIfVisible(   "getNextSibling()     = ", node.getNextSibling() );
        }
        System.out.println(    "----------------------\n" );
      }
*/
    public  String streamToString (InputStream in) throws IOException {
         StringBuffer out = new StringBuffer();
         byte[] b = new byte[4096];
         for (int n; (n = in.read(b)) != -1;) {
             out.append(new String(b, 0, n));
         }
         return out.toString();
     }

   

}
